package com.gitee.zjbqdzq.core;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public record NnyyResource(Map<String, String> urls, String filename) implements Resource {
    private static final Logger log = LoggerFactory.getLogger(NnyyResource.class);
    private static final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    @Override
    public String getUrl() {
        return sortUrls().getFirst();
    }

    @Override
    public String getFilename() {
        return filename;
    }

    public List<String> sortUrls() {
        Collection<String> values = urls.values();
        Comparator<JSONObject> width = Comparator.comparing(t -> t.getInt("width"));
        width = width.thenComparing(t -> t.getInt("height"));
        width = width.reversed();
        width = width.thenComparing(t -> t.getInt("responseTime"));
        List<JSONObject> list = values.stream()
                .map(this::parse)
                .map(this::waitFor).filter(Objects::nonNull)
                .map(json -> {
                    JSONArray streams = json.getJSONArray("streams");
                    if (Objects.isNull(streams)) {
                        return null;
                    }
                    JSONObject entries = ((JSONObject) streams.getFirst());
                    entries.set("responseTime", json.getInt("responseTime"));
                    entries.set("url", json.getStr("url"));
                    return streams;
                })
                .filter(Objects::nonNull)
                .map(JSONArray::getFirst)
                .map(JSONObject.class::cast)
                .sorted(width)
                .toList();
        String result = list.stream().map(v -> v.toJSONString(2)).collect(Collectors.joining("\n"));
        System.out.println(result);
        return list.stream().map(json -> json.getStr("url")).toList();
    }

    private JSONObject waitFor(CompletableFuture<JSONObject> future) {
        try {
            return future.get(20, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException e) {
            log.error(e.getMessage(), e);
        } catch (TimeoutException e) {
            log.error("等待超时");
            future.cancel(true);
        }
        return null;
    }

    private CompletableFuture<JSONObject> parse(String url) {
        return CompletableFuture.supplyAsync(() -> getStreamInfo(url), executor);
    }

    private static JSONObject getStreamInfo(String url) {
        try (InputStream is = RuntimeUtil.exec("ffprobe", "-i", url, "-select_streams", "v:0", "-show_entries", "stream=width,height", "-loglevel", "error", "-print_format", "json").getInputStream()) {
            long l = System.currentTimeMillis();
            String s = IoUtil.readUtf8(is);
            l = System.currentTimeMillis() - l;
            try {
                JSONObject entries = JSONUtil.parseObj(s);
                entries.set("responseTime", l);
                entries.set("url", url);
                return entries;
            } catch (JSONException e) {
                log.error("url: {}, 解析json异常. {}", url, s);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
}
